package com.todo.biz.application.job;

import cn.hutool.core.util.NumberUtil;
import com.alibaba.fastjson.JSONObject;
import com.todo.biz.application.entity.BizBaseRedisKeyUtil;
import com.todo.biz.application.entity.bo.BizCounterBO;
import com.todo.biz.application.mq.entity.BizCountMQEntity;
import com.todo.biz.application.mq.sender.BizCounterMqSender;
import com.todo.biz.application.service.BizCounterService;
import com.todo.biz.common.enums.CounterTypeEnum;
import com.todo.common.common.enums.BusinessSceneEnum;
import com.todo.common.utils.StringUtils;
import com.todo.common.utils.TodoCommonUtils;
import com.todo.component.redis.RedisService;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.Date;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * @author azhebuxing
 * @date 2024/5/8 15:06
 * @description
 */
@Slf4j
@Component
public class CounterCacheToDBJob {

    /**
     * 线程池执行
     */
    ThreadPoolExecutor executor = new ThreadPoolExecutor(30, 30, 10000, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(1000));

    @Resource
    private BizCounterMqSender bizCounterMqSender;

    @Resource
    private RedisService redisService;
    @Resource
    private BizCounterService bizCounterService;

    @XxlJob("counterCacheToDBJob")
    public void execute() {
        log.info("CounterCacheToDBJob#execute 计数信息缓存同步DB 开始执行");

        BusinessSceneEnum[] businessSceneEnumList = BusinessSceneEnum.values();
        CounterTypeEnum[] counterTypeEnums = CounterTypeEnum.values();

        for (BusinessSceneEnum businessSceneEnum : businessSceneEnumList) {
            for (long bucket = 0; bucket < TodoCommonUtils.DEFAULT_BUCKET_SIZE_100; bucket++) {
                long finalBucket = bucket;
                CompletableFuture.runAsync(() -> doExecute(businessSceneEnum, finalBucket), executor);
            }
        }
    }

    /**
     * 具体执行
     *
     * @param businessSceneEnum
     * @param bucket
     * @return
     */
    private void doExecute(BusinessSceneEnum businessSceneEnum, Long bucket) {
        if (businessSceneEnum == null || bucket == null) {
            return;
        }

        for (CounterTypeEnum typeEnum : CounterTypeEnum.values()) {
            String bizCounterIdKey = BizBaseRedisKeyUtil.getBizCounterIdKey(businessSceneEnum, typeEnum, bucket);
            Set<String> businessKeySet = redisService.sMembers(bizCounterIdKey);
            if (CollectionUtils.isEmpty(businessKeySet)) {
                log.warn("CounterCacheToDBJob#doExecute 具体执行查询所有set集合为空 key：【{}】", bizCounterIdKey);
                return;
            }
            for (String businessKey : businessKeySet) {
                String bizCounterCountKey = BizBaseRedisKeyUtil.getBizCounterCountKey(businessSceneEnum, typeEnum, Long.valueOf(businessKey));
                String countStr = redisService.get(bizCounterCountKey);
                if (StringUtils.isBlank(countStr) || !NumberUtil.isNumber(countStr)) {
                    log.warn("CounterCacheToDBJob#doExecute 具体执行查询当前业务数据下数量为空 key：【{}】，countStr：【{}】", bizCounterCountKey, countStr);
                    return;
                }
                Integer count = Integer.valueOf(countStr);
                BizCounterBO bizCounterBO = bizCounterService.queryBizCounterByBizIdAndSceneAndType(Long.valueOf(businessKey), businessSceneEnum, typeEnum);
                if (bizCounterBO == null) {
                    BizCounterBO insertData = new BizCounterBO();
                    insertData.setId(TodoCommonUtils.buildLongGuid());
                    insertData.setBusinessId(Long.valueOf(businessKey));
                    insertData.setCounterType(typeEnum);
                    insertData.setBusinessScene(businessSceneEnum);
                    insertData.setCount(count);
                    insertData.setLastCalTime(new Date());
                    Boolean insertResult = bizCounterService.insertBizCounter(insertData);
                    if (insertResult) {
                        redisService.del(bizCounterCountKey);
                        redisService.sRemove(bizCounterIdKey, businessKey);
                    }
                    log.info("CounterCacheToDBJob#doExecute 根据类型以及业务数据查询计数信息为空 默认新建对象 insertData:【{}】,insertResult:【{}】", JSONObject.toJSONString(insertData), insertResult);
                    return;
                }
                Integer origin = bizCounterBO.getCount();
                bizCounterBO.setCount(origin + count);
                bizCounterBO.setLastCalTime(new Date());
                Boolean updateResult = bizCounterService.updateBizCounter(bizCounterBO);
                if (updateResult) {
                    redisService.del(bizCounterCountKey);
                    redisService.sRemove(bizCounterIdKey, businessKey);
                }
                log.info("CounterCacheToDBJob#doExecute 根据类型以及业务数据查询计数信息不为空 更新对象 bizCounterBO:【{}】,updateResult:【{}】", JSONObject.toJSONString(bizCounterBO), updateResult);
            }
            for (String businessKey : businessKeySet) {
                BizCountMQEntity entity = new BizCountMQEntity();
                entity.setBizId(Long.valueOf(businessKey));
                entity.setBizScene(businessSceneEnum);
                sendBizCounterMQ(entity);
            }
        }
    }

    private void sendBizCounterMQ(BizCountMQEntity entity) {
        if (entity == null) {
            return;
        }
        if (BusinessSceneEnum.SIGHT.equals(entity.getBizScene())) {
            bizCounterMqSender.sendSightCounter(entity, 0);
        }
        if (BusinessSceneEnum.PLATFORM_STRATEGY.equals(entity.getBizScene())) {
            bizCounterMqSender.sendPlatformStrategyCounter(entity, 0);
        }
        if (BusinessSceneEnum.STRATEGY.equals(entity.getBizScene())) {
            bizCounterMqSender.sendUserStrategyCounter(entity, 0);
        }
        if (BusinessSceneEnum.CONTENT.equals(entity.getBizScene())) {
            bizCounterMqSender.sendContentCounter(entity, 0);
        }

    }
}
